<?php
namespace Plu\Library\Error;

/**
 * 错误抓捕处理工具，将所有错误记录到log系统中
 *
 * $errorHandler = new ErrorHandler($logger);
 * $errorHandler->register();
 */

class ErrorHandler {
    public function __construct($logger, $options = []) {
        $this->logger = $logger;
        $this->options = $options;
    }

    public function register() {
        //no Yac , no custom log view;
        if(!class_exists("\\Yac")){
            trigger_error('No Yac installed', E_USER_WARNING);
            return;
        }

        $level = -1;
        if (isset($this->options['errorLevel'])) {
            $level = $this->options['errorLevel'];
        }
        error_reporting($level);

        set_error_handler([$this, 'handleError'], $level);

        set_exception_handler([$this, 'handleException']);

        register_shutdown_function(function() {
            if (PHP_SAPI == 'phpdbg') {
                return;
            }

            $error = error_get_last();
            if (!is_array($error)) {
                return;
            }

            $fatals = [
                E_USER_ERROR,
                E_ERROR,
                E_PARSE,
            ];

            if (!in_array($error["type"], $fatals, true)) {
                return;
            }

            $this->handleError($error['type'], $error['message'], $error['file'], $error['line']);
        });
    }

    public function handleException($e) {
        $this->logger->error($e->getMessage(), [
            'code'   => $e->getCode(),
            'msg'    => $e->getMessage(),
            'file'   => $e->getFile(),
            'line'   => $e->getLine(),
            'trace'  => $e->getTraceAsString()
        ]);

        // Error/Exception 可能有多个全部抛出
        if ($error = $e->getPrevious()) {
            $this->handleException($error);
        }
    }

    public function handleError($errno, $errstr, $errfile, $errline) {
        switch ($errno) {
            case E_ERROR:
            case E_CORE_ERROR:
            case E_PARSE:
            case E_COMPILE_ERROR:
            case E_USER_ERROR:
            case E_RECOVERABLE_ERROR:
                $type = \Phalcon\Logger::ERROR;
                break;
            case E_STRICT:
                $type = \Phalcon\Logger::CRITICAL;
                break;
            case E_WARNING:
            case E_CORE_WARNING:
            case E_COMPILE_WARNING:
            case E_USER_WARNING:
                $type = \Phalcon\Logger::WARNING;
                break;
            case E_USER_NOTICE:
            case E_NOTICE:
            case E_DEPRECATED:
            case E_USER_DEPRECATED:
                $type = \Phalcon\Logger::NOTICE;
                break;
            default:
                $type = \Phalcon\Logger::DEBUG;
                break;
        }

        $this->logger->log($type, $errstr, [
            'code'    => $errno,
            'file'    => $errfile,
            'line'    => $errline
        ]);
    }
}
